TypeScript is a natural extension of JavaScript that’s used in many projects in place of JavaScript.
However, not everyone knows how it actually works.
In this article, we’ll look at how to define and use arrays in our TypeScript code.
Working with Arrays
JavaScript arrays can contain data from any combination of types and have variable lengths.
Items can be added or removed without the needed to resize the array explicitly.
TypeScript doesn’t change the flexible array sizing, but we can use it to restrict the types of data that can be in an array.
For instance, we can write:
let prices: number[] = [48, 23, 41];
to restrict the prices
array to only hold numbers.
number
is the data type of each entry and []
indicates that it’s an array.
We can also use parentheses to indicate that an array can hold entries with different types of data.
For instance, we can write:
let prices: (number | string)[] = [48, 23, '88'];
So that prices
can have strings in addition to numbers.
TypeScript will ensure that only operations that are allowed for number values are performed by the function.
Equivalent Array Syntax
We can specify the array data type with brackets.
For instance, we can write:
let prices: Array<number> = [48, 23, 88];
which is the same as:
let prices: number[] = [48, 23, 88];
Inferred Typing for Arrays
If the data type is obvious from the values, then we don’t have to write the data type annotation explicitly.
For instance, we can write:
let prices = [48, 23, 88];
The TypeScript compiler will know that we have a number array just from the assignment.
We can see that if we loop through the array with forEach
and try to do something with each entry:
let prices: number[] = [48, 23, 88];
prices.forEach(p => {
console.log(p.toFixed(2));
});
The compiler lets us call the toFixed
method on an array, which is a method available for numbers.
It’s great at inferring type from existing values.
Problems with Inferred Array Types
We may run into problems if we have a possibility of type mismatches.
For instance, we can write:
const prices: number[] = [48, 23, 88];
const taxes: number[] = [];
const getTax = (price: number, format: boolean) => {
if (format) {
return (price * 0.2).toFixed(2);
}
return price * 0.2;
};
prices.forEach(p => {
taxes.push(getTax(p, false));
});
We’ll get the error:
Argument of type 'string | number' is not assignable to parameter of type 'number'.
Type 'string' is not assignable to type 'number'.ts(2345)
from the compiler since getTax
may return a number or a string.
Even if we pass in false
, which should return a number, the compiler isn’t smart enough to figure that out on its own.
Therefore, we can either set the type of taxes
to be number | string
.
Or we can assert that each entry is a number.
Empty Arrays
If we have an empty array, the type would be inferred as any[]
implicitly.
To avoid this, we should specify the type of it explicitly.
This applies if strictNullChecks
is set to false
.
never Array Type
When null
and undefined
aren’t assignable to other types, Typescript infers to empty arrays differently.
It’ll have the never
type instead of any[]
if strictNullChecks
is set to true
.
Inferring the type as never
ensures that the array doesn’t escape any type checking process and the code won’t compile until the type of each entry is asserted or the array is initialized to the values that let the compiler infer the type.
Conclusion
TypeScript can infer the types of arrays if entries are added explicitly.
Inferred array types are different for empty arrays depending if strictNullChecks
is true
or not in the compiler options.
We can also set the type of arrays explicitly.
The TypeScript compiler isn’t smart enough to infer all data types on its own.
So data type assertions may be needed.